package cz.vse.javaee.album;

import javax.annotation.Resource;
import javax.ejb.*;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Keš ikon fotografií.
 * <p/>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Apr 6, 2010
 * Time: 8:30:37 PM
 */
@Singleton
@Lock(LockType.WRITE)
public class PhotoCache implements PhotoCacheRemote {

    private static final Logger logger = Logger.getLogger(PhotoCache.class.getName());

    private Map<String, Photo> cache = new HashMap<String, Photo>();
    private Map<Integer, Photo> cacheById = new HashMap<Integer, Photo>();

    @PersistenceContext(unitName = "album")
    private EntityManager entityManager;

    @Resource(name = "iconWidth")
    private int iconWidth;

    public Photo getIconByName(String photoName) throws NoPhotoFoundException {
        try {
//            Photo icon;
            Photo icon = cache.get(photoName);
            if (icon == null) {
                // Získáme originál
                Query query = entityManager.createQuery("select p from Photo p where p.name=:name");
                query.setParameter("name", photoName);
                icon = (Photo) query.getSingleResult();
                // Musíme nahrát data obrázku do entity
                // kvůli FetchType.LAZY
                icon.getImage();
                // Odpojíme fotku, aby se změny ve velikosti
                // neprojevily v databázi
                entityManager.detach(icon);

                // Zmenšíme fotku na ikonu
                icon.resize(iconWidth, iconWidth);
                // Uložíme do keše
                cache.put(photoName, icon);
                cacheById.put(icon.getId(), icon);
            }
            return icon;
        } catch (NoResultException e) {
            throw new NoPhotoFoundException(photoName);
        }
    }

    @Schedule(second = "*/10", minute = "*", hour = "*", persistent = false)
    public void cleanCache() {
        // Pokud je keš prázdná, není co uklízet
        if (cache.isEmpty()) {
            return;
        }

        // Připravíme si seznam názvů fotek oddělený ','.
        // Tento seznam se použije v dotazu za operátorem IN.
        StringBuilder photosId = buildNamesSequence();

        // Vybereme všechny fotky, které jsou v keši. Operátor IN
        // zařídí výběr specifikovaných fotek.
        Query query = entityManager.createQuery("select p.name, p.version from Photo p where p.id in (" + photosId + ")");
        // Výsledek je seznam dvojic (name, version)
        List<Object[]> nameVersionPairs = query.getResultList();

        // V cyklu porovnáme aktuální verzi fotky s verzí ikony
        for (Object[] nameVersionPair : nameVersionPairs) {
            String photoName = (String) nameVersionPair[0];
            int versionInDb = (Integer) nameVersionPair[1];
            Photo icon = cache.get(photoName);
            // Porovnání verzí
            if (versionInDb > icon.getVersion()) {
                cache.remove(photoName);
                cacheById.remove(icon.getId());
                logger.info("Icon " + photoName + " removed from the cache");
            }
        }
    }

    private StringBuilder buildNamesSequence() {
        StringBuilder photosId = new StringBuilder();
        boolean first = true;
        for (Photo photo : cache.values()) {
            if (!first) {
                photosId.append(',');
            } else {
                first = false;
            }
            photosId.append(photo.getId());
        }
        return photosId;
    }

    public void syncPhoto(int id) {
        Photo icon = cacheById.get(id);
        if (icon == null) {
            return;
        }
        cacheById.remove(id);
        cache.remove(icon.getName());
    }

}
